package com.cpr.core.bio;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Chen Panrui
 * created at 2021/12/24 17:55
 */
public class BioServer {

    public static void main(String[] args) throws IOException {
        ExecutorService executorService = initExecutorService();
        ServerSocket serverSocket = new ServerSocket(9999);
        // 服务已启动
        System.out.println("服务器已启动...");
        while (!Thread.currentThread().isInterrupted()){
            // accept方法是阻塞的，必须有client连接才会通过
            final Socket socket = serverSocket.accept();
            System.out.println("有客户端连接...");
            // 把业务操作交给线程池，使main线程可以理解去接收client的socket的连接请求
            executorService.execute(() -> {
                handle(socket);
            });
        }
        // 关闭服务器的 socket 通道
        serverSocket.close();
    }

    public static void handle(Socket socket){
        try {
            // 从socket获取 客户端的输入流，此方法也是阻塞的，如果客户端连接后，没有输出东西，也会在这个方法阻塞等待client的输出
            InputStream input = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int read = input.read(bytes);
            System.out.println("客户端输入:" + new String(bytes,0,read));
            OutputStream output = socket.getOutputStream();
            // 假设我们有自定义的逻辑处理，需要耗时2s
            TimeUnit.SECONDS.sleep(2);
            // 从socket获取 输出流，写入消息，返回给客户端，如果此方法阻塞
            output.write("没钱".getBytes(StandardCharsets.UTF_8));
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static ExecutorService initExecutorService(){
        return new ThreadPoolExecutor(1,
                1,
                600L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),
                new ThreadPoolExecutor.AbortPolicy());
    }
}
